package com.mall.gateway.config;

import com.mall.common.result.Result;
import com.mall.common.util.JwtUtil;
import com.mall.common.util.RedisUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.SignatureException;
import io.jsonwebtoken.UnsupportedJwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;

/**
 * 网关配置类
 */
@Slf4j
@Configuration
public class GatewayConfig {

    /**
     * JWT密钥
     */
    @Value("${jwt.secret:mall-secret}")
    private String jwtSecret;

    @Autowired
    private RedisUtil redisUtil;
    
    private AntPathMatcher pathMatcher = new AntPathMatcher();

    /**
     * 不需要认证的路径
     */
    private static final List<String> WHITE_LIST = new ArrayList<>();

    static {
        // 登录接口
        WHITE_LIST.add("/auth/login");
        // 注册接口
        WHITE_LIST.add("/auth/register");
        // 获取验证码
        WHITE_LIST.add("/auth/captcha");
        // 登出接口
        WHITE_LIST.add("/auth/logout");
        // 第三方扫码登录相关接口
        WHITE_LIST.add("/auth/qr/generate/**");
        WHITE_LIST.add("/auth/qr/check/**");
        // OAuth2.0回调接口（第三方平台回调，不能带JWT Token）
        WHITE_LIST.add("/auth/oauth2/callback/**");
        // Swagger UI相关路径
        WHITE_LIST.add("/swagger-ui.html");
        WHITE_LIST.add("/swagger-ui/**");
        WHITE_LIST.add("/swagger-ui/index.html");
        WHITE_LIST.add("/v3/api-docs/**");
        WHITE_LIST.add("/v3/api-docs");
        WHITE_LIST.add("/webjars/**");
        WHITE_LIST.add("/doc.html");
        WHITE_LIST.add("/swagger-resources/**");
    }

    /**
     * 全局过滤器
     *
     * @return 过滤器
     */
    @Bean
    public GlobalFilter globalFilter() {
        return new GlobalFilter() {
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
                ServerHttpRequest request = exchange.getRequest();
                ServerHttpResponse response = exchange.getResponse();

                // 请求路径
                String path = request.getPath().toString();
                log.info("接收到请求: {}", path);

                // 白名单路径直接放行
                if (isWhiteListPath(path)) {
                    return chain.filter(exchange);
                }

                // JWT Token验证逻辑
                String authorization = request.getHeaders().getFirst("Authorization");
                if (authorization == null || !authorization.startsWith("Bearer ")) {
                    return unauthorizedResponse(response, "缺少有效的Authorization头");
                }

                // 提取Token
                String token = authorization.substring(7);
                
                // 检查Token是否在黑名单中
                try {
                    Object blacklistValue = redisUtil.get("token:blacklist:" + token);
                    if ("true".equals(blacklistValue)) {
                        return unauthorizedResponse(response, "Token已被登出");
                    }
                } catch (Exception e) {
                    log.error("检查Token黑名单状态失败: {}", e.getMessage());
                }

                try {
                    // 使用JWT工具类验证Token
                    if (!JwtUtil.validateToken(token, jwtSecret)) {
                        return unauthorizedResponse(response, "Token验证失败");
                    }

                    // 解析Token获取用户信息
                    Claims claims = JwtUtil.parseToken(token, jwtSecret);

                    // 将用户信息添加到请求头中，供下游服务使用
                    ServerHttpRequest mutatedRequest = request.mutate()
                            .header("user_id", String.valueOf(claims.get("userid")))
                            .header("username", String.valueOf(claims.get("username")))
                            .header("nickname", String.valueOf(claims.get("nickname")))
                            .build();

                    ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).build();
                    return chain.filter(mutatedExchange);
                } catch (ExpiredJwtException e) {
                    log.error("Token已过期: {}", e.getMessage());
                    return unauthorizedResponse(response, "Token已过期");
                } catch (UnsupportedJwtException e) {
                    log.error("不支持的Token: {}", e.getMessage());
                    return unauthorizedResponse(response, "不支持的Token");
                } catch (MalformedJwtException e) {
                    log.error("Token格式错误: {}", e.getMessage());
                    return unauthorizedResponse(response, "Token格式错误");
                } catch (SignatureException e) {
                    log.error("Token签名异常: {}", e.getMessage());
                    return unauthorizedResponse(response, "Token签名异常");
                } catch (Exception e) {
                    log.error("Token验证异常: {}", e.getMessage());
                    return unauthorizedResponse(response, "Token验证异常");
                }
            }
        };
    }

    /**
     * 判断路径是否在白名单中
     * 
     * @param path 请求路径
     * @return 是否在白名单中
     */
    private boolean isWhiteListPath(String path) {
        for (String whitePath : WHITE_LIST) {
            if (pathMatcher.match(whitePath, path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 返回未授权响应
     *
     * @param response 响应对象
     * @param message  错误消息
     * @return Mono<Void>
     */
    private Mono<Void> unauthorizedResponse(ServerHttpResponse response, String message) {
        response.setStatusCode(HttpStatus.UNAUTHORIZED);
        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
        Result<Object> result = Result.unauthorized();
        result.setMessage(message);
        String resultStr = com.alibaba.fastjson.JSON.toJSONString(result);
        DataBuffer buffer = response.bufferFactory().wrap(resultStr.getBytes(StandardCharsets.UTF_8));
        return response.writeWith(Mono.just(buffer));
    }

    /**
     * 排序配置
     */
    @Configuration
    public class FilterOrderConfig implements Ordered {
        @Override
        public int getOrder() {
            return 0;
        }
    }
}